package com.xiyan.base.controller;

import cn.hutool.core.util.ObjectUtil;
import com.xiyan.base.entity.User;
import com.xiyan.base.service.IUserService;
import com.xiyan.base.utils.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @program: shiro
 * @description: login&logout controller
 * @author: ruiyanglee
 * @create: 2020-07-23 16:16
 **/

@RestController
@RequestMapping("/auth")
@Api(value = "Shiro api", tags = "认证接口")
public class ShiroController {
    public static final Logger log = LoggerFactory.getLogger(ShiroController.class);

    @Resource
    private IUserService userService;
    @Resource
    private RedisUtil redisUtil;

    @ApiOperation("登录接口")
    @RequestMapping(value = "/login", method = RequestMethod.POST)
    @ResponseBody
    public ResponseResult login(@RequestBody User user,
                                HttpServletResponse response) {
        try {
            String username = user.getUsername();
            String password = user.getPassword();
            User currentUser = userService.findByUsername(username);
            if (ObjectUtil.isNull(currentUser)) {
                return ResponseResult.error().code(ResultCode.USER_NAME_NOT_EXIST_CODE).message("登录失败，账户不存在");
            }
            String salt = currentUser.getPrivateSalt();
            Md5Hash md5Hash = new Md5Hash(password, salt, 1);
            if (!md5Hash.toString().equals(currentUser.getPassword())) {
                return ResponseResult.error().code(ResultCode.USER_PASSWD_ERROR_CODE).message("登录失败，密码错误");
            }

            String token = JWTUtil.sign(username);
            response.setHeader("Authorization", token.toString());
            response.setHeader("Access-Control-Expose-Headers", "Authorization");
            // 设置token缓存有效时间
            redisUtil.set(Constant.TOKEN_PREFIX + username, token);
            redisUtil.expire(Constant.TOKEN_PREFIX + username, Constant.EXPIRE_TIME);

            return ResponseResult.ok().message("登录成功").data(token);
        } catch (IncorrectCredentialsException e) {
            log.error("login interface exception info {}", e.getMessage());
            return ResponseResult.error().message("登录失败，请重新登录");
        }
    }

    @ApiOperation("退出接口")
    @RequestMapping(value = "/logout", method = RequestMethod.GET)
    @ResponseBody
    public ResponseResult logout(HttpServletRequest request) {
        try {
            String token = request.getHeader(Constant.TOKEN);
            String username = JWTUtil.getUsername(token);
            redisUtil.del(Constant.TOKEN_PREFIX + username);
            Subject subject = SecurityUtils.getSubject();
            subject.logout();
            return ResponseResult.ok().message("退出成功");
        } catch (Exception e) {
            log.error("logout interface exception info {}", e.getMessage());
            return ResponseResult.error();
        }
    }

    @ApiOperation("用户注册接口")
    @RequestMapping(value = "/add", method = RequestMethod.POST)
    @ResponseBody
    public ResponseResult add(@RequestBody User user) {
        try {
            String password = user.getPassword();
            user.setPrivateSalt(Constant.PRIVATE_SALT);
            // 对密码进行加密
            Md5Hash md5Hash = new Md5Hash(password, Constant.PRIVATE_SALT, 1);
            user.setPassword(md5Hash.toString());
            userService.save(user);
            System.out.println(user.toString());
            return ResponseResult.ok().message("用户新增成功");
        } catch (Exception e) {
            log.error("add interface exception info {}", e.getMessage());
            return ResponseResult.error().message("注册失败");
        }
    }
}
